﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RailroadDal
{
    public static class RailroadDao
    {
        private const int TIME_ON_STATION = 5;
        public static void CreateStation(Station station) 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            entities.Stations.AddObject(station);
            entities.SaveChanges();
        }

        public static IEnumerable<Station> GetAllStations() 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            var stations = entities.Stations;
            return stations;
        }

        public static Station GetStationById(int stationId, RaiwayCompanyEntities entities)
        {
            Station station = entities.Stations.FirstOrDefault(s=>s.StationId == stationId);
            return station;
        }

        public static void UpdateStation(Station station, int stationId)
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Station toUpdate = GetStationById(stationId, entities);
            toUpdate.StationName = station.StationName;
            toUpdate.OffsetX = station.OffsetX;
            toUpdate.OffsetY = station.OffsetY;
            entities.SaveChanges();
        }

        public static void DeleteStation(int stationId)
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Station toDelete = GetStationById(stationId, entities);
            var rautes = toDelete.Rautes;
            if (rautes.Count != 0) 
            {
                throw new ArgumentException("This station has rautes");
            }
            //foreach (var raute in rautes)
            //{
            //    entities.Rautes.DeleteObject(raute);
            //}
            var distancces = toDelete.Distances;
            foreach (var distance in distancces)
            {
                entities.Distances.DeleteObject(distance);
            }
            distancces = toDelete.Distances1;
            foreach (var distance in distancces)
            {
                entities.Distances.DeleteObject(distance);
            }
            entities.Stations.DeleteObject(toDelete);
            entities.SaveChanges();
        }

        public static void CreateDistance(int startStationId, int endStationId, int timeInMinutes) 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Distance newDistance = entities.Distances.CreateObject();
            newDistance.StartingStationId = startStationId;
            newDistance.EndStationId = endStationId;
            newDistance.TravelTimeInMinutes = timeInMinutes;
            entities.SaveChanges();
        }

        public static Distance GetDistanceById(int distanceId, RaiwayCompanyEntities entities)
        {
            Distance distance = entities.Distances.FirstOrDefault(d=> d.DistanceId == distanceId);
            return distance;
        }

        public static IEnumerable<Distance> GetAllDistances() 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            var distances = entities.Distances;
            return distances;
        }

        public static void DeleteDistance(int distanceID) 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Distance toDelete = GetDistanceById(distanceID, entities);
            entities.Distances.DeleteObject(toDelete);
            entities.SaveChanges();
        }

        public static void UpdateDistance(Distance newDistance, int distanceId) 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Distance toUpdate = GetDistanceById(distanceId, entities);
            toUpdate.StartingStationId = newDistance.StartingStationId;
            toUpdate.EndStationId = newDistance.EndStationId;
            toUpdate.TravelTimeInMinutes = newDistance.TravelTimeInMinutes;
            entities.SaveChanges();
        }

        public static void CreateRaute(DateTime statrtTime, List<int> stationIds)
        {
            if (stationIds.Count < 2) 
            {
                throw new ArgumentOutOfRangeException("Raute must have atleast two stations");
            }
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Raute newRaute = entities.Rautes.CreateObject();
            newRaute.StartTime = statrtTime;
            foreach (var id in stationIds)
            {
                Station station = GetStationById(id, entities);
                newRaute.Stations.Add(station);
            }
            entities.SaveChanges();
        }

        public static Raute GetRauteById(int rauteId, RaiwayCompanyEntities entities) 
        {
            Raute raute = entities.Rautes.FirstOrDefault(r => r.RouteId == rauteId);
            return raute;
        }

        public static void DeleteRoute(int rauteId) 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Raute toDelete = GetRauteById(rauteId, entities);
            entities.Rautes.DeleteObject(toDelete);
            entities.SaveChanges();
        }

        public static void UpdateRaute(Raute newRaute, int rauteId) 
        {
            DeleteRoute(rauteId);
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            entities.Rautes.Attach(newRaute);
            entities.SaveChanges();
        }

        public static IEnumerable<Raute> GetAllRautesThroughStation(int stationId) 
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Station station = GetStationById(stationId, entities);
            return station.Rautes;
        }

        public static List<Raute> GetAllDirectRautes(int start, int end)
        {
            RaiwayCompanyEntities entities = new RaiwayCompanyEntities();
            Station startStation = entities.Stations.Include("Rautes").Include("Rautes.Stations").
                FirstOrDefault(s => s.StationId == start);
            Station endStation = GetStationById(end, entities);
            List<Raute> rautes = new List<Raute>();
            foreach (var raute in startStation.Rautes)
            {
                if (raute.Stations.Count == 2 && raute.Stations.Contains(endStation)) 
                {
                    rautes.Add(raute);
                }
            }
            rautes.OrderBy(r => r.StartTime);
            return rautes;
        }

        public static List<TimeTableEntery> CreateTimeTable(int ratuteId) 
        {
            RaiwayCompanyEntities entitie = new RaiwayCompanyEntities();
            Raute raute = entitie.Rautes.Include("Stations").Include("Stations.Distances").FirstOrDefault
                (r => r.RouteId == ratuteId);
            List<Station> stations = raute.Stations.ToList<Station>();
            List<TimeTableEntery> table = new List<TimeTableEntery>();
            DateTime current = raute.StartTime;
            for (int i = 0; i < stations.Count; i++)
            {
                TimeTableEntery entery = new TimeTableEntery();
                if (i == 0) 
                {
                    entery.StationName = stations[i].StationName;
                    entery.Arrive = raute.StartTime;
                    entery.Depart = raute.StartTime;
                }
                if (i!=0) 
                {
                    int time=stations[i - 1].Distances.FirstOrDefault(d => d.EndStation == stations[i]).TravelTimeInMinutes;
                    if (time == 0) 
                    {
                        time = stations[i].Distances.FirstOrDefault(d => d.EndStation == stations[i-1]).TravelTimeInMinutes;
                        if (time == 0) 
                        {
                            throw new ArgumentOutOfRangeException("invalid raute");
                        }
                    }
                    current = current.AddMinutes(time);
                    entery.StationName = stations[i].StationName;
                    entery.Arrive = current;
                    if (i + 1 < stations.Count)
                    {
                        current = current.AddMinutes(TIME_ON_STATION);
                        entery.Depart = current;
                    }
                    else 
                    {
                        entery.Depart = current;
                    }
                }
                table.Add(entery);
            }
            return table;
        }

    }
}
